<?php
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

/**
 * Saved Search
 *
 * Serialized search parameters, public or private.
 *
 * @package default
 */
class SavedSearch extends AIR2_Record {

    /**
     * Set the table columns
     */
    public function setTableDefinition() {
        $this->setTableName('saved_search');
        $this->hasColumn('ssearch_id', 'integer', 4, array(
                'primary' => true,
                'autoincrement' => true,
            )
        );
        $this->hasColumn('ssearch_name', 'string', 255, array(
                'notnull' => true,
                'default' => 'My Search',
                'unique'  => true,
            )
        );
        $this->hasColumn('ssearch_public_flag', 'boolean', null, array(
                'notnull' => true,
                'default' => 0,
            )
        );
        $this->hasColumn('ssearch_params', 'string', null, array(
                'notnull' => true,
            )
        );
        $this->hasColumn('ssearch_cre_user', 'integer', 4, array(
                'notnull' => true,
            )
        );
        $this->hasColumn('ssearch_upd_user', 'integer', 4, array(

            )
        );
        $this->hasColumn('ssearch_cre_dtim', 'timestamp', null, array(
                'notnull' => true,
            )
        );
        $this->hasColumn('ssearch_upd_dtim', 'timestamp', null, array(

            )
        );
        $this->hasColumn('ssearch_uuid', 'string', 12, array(
                'fixed' => true,
                'notnull' => true,
                'unique' => true,
            )
        );

        parent::setTableDefinition();
    }



    /**
     * Set table relations
     */
    public function setUp() {
        parent::setUp();

        $this->hasMany('ProjectSavedSearch as Projects', array(
                'foreign' => 'pss_ssearch_id',
                'local' => 'ssearch_id'
            )
        );
    }



    /**
     *
     *
     * @param array   $projects
     */
    public function add_projects(array $projects) {
        foreach ($projects as $p) {
            $pss = new ProjectSavedSearch();
            $pss->pss_prj_id    = $p->prj_id;
            $pss->pss_ssearch_id = $this->ssearch_id;
            $this->Projects[] = $pss;
        }
    }


    /**
     * Add custom search query (from the get param 'q')
     *
     * @param AIR2_Query $q
     * @param string  $alias
     * @param string  $search
     * @param boolean $useOr
     */
    public static function add_search_str(&$q, $alias, $search, $useOr=null) {
        $a = ($alias) ? "$alias." : "";
        $str = "(".$a."ssearch_name LIKE ? )";
        $q->addWhere($str, array("%$search%"));
    }


    /**
     * Apply authz rules for who may view the existence of a Saved Search.
     *
     * @param AIR2_Query $q     (reference)
     * @param User    $u     (reference)
     * @param string  $alias (optional)
     */
    public static function query_may_read(AIR2_Query &$q, User &$u, $alias=null) {
        $a = ($alias) ? "$alias." : "";
        $user_id = $u->user_id;

        // subqueries
        $uo_act = UserOrg::$STATUS_ACTIVE;
        $po_act = ProjectOrg::$STATUS_ACTIVE;
        $my_orgs = "select uo_org_id from user_org where uo_user_id = $user_id".
            " and uo_status = '$uo_act'";
        $my_prjs = "select porg_prj_id from project_org where porg_org_id in ($my_orgs)".
            " and porg_status = '$po_act'";
        $ssearch_orgs = "select uo_org_id from user_org where uo_user_id = ${a}ssearch_cre_user".
            " and uo_status = '$uo_act'";
        $ssearch_prjs = "select pss_prj_id from project_saved_search where pss_ssearch_id = ${a}ssearch_id";

        // queries to count common orgs/projects between remote user and ssearch user
        $common_prjs = "select count(*) from ($my_prjs) spr where porg_prj_id in ($ssearch_prjs)";
        $common_orgs = "select count(*) from ($my_orgs) mor where uo_org_id in ($ssearch_orgs)";

        // add selects (for fun), but where condition is the important part
        $q->addSelect("($common_orgs) as shared_orgs");
        $q->addSelect("($common_prjs) as shared_prjs");
        $shared = "${a}ssearch_public_flag = true AND ((($common_orgs) > 0) OR (($common_prjs) > 0))";
        $q->addWhere("(${a}ssearch_cre_user = $user_id) OR ($shared)");

    }


    /**
     * Apply authz rules for who may view the existence of a Saved Search.
     *
     * @param AIR2_Query $q     (reference)
     * @param User    $u     (reference)
     * @param string  $alias (optional)
     */
    public static function query_may_write(AIR2_Query &$q, User &$u, $alias=null) {
        $a = ($alias) ? "$alias." : "";
        $user_id = $u->user_id;

        $q->addWhere("${a}ssearch_cre_user = ?", $user_id);

    }


    /**
     *
     *
     * @param unknown $q     (reference)
     * @param unknown $u     (reference)
     * @param unknown $alias (optional)
     * @return unknown
     */
    public static function query_may_manage(AIR2_Query &$q, User &$u, $alias=null) {
        return self::query_may_write($q, $u, $alias);
    }





    /**
     *
     *
     * @return array $org_ids
     */
    private function _get_proj_org_ids() {
        $proj_org_ids = array();
        $projects = $this->Projects;
        foreach ($projects as $pss) {
            $proj_org_ids = array_merge($proj_org_ids, $pss->Project->get_authz());
        }
        return $proj_org_ids;
    }


    /**
     *
     *
     * @param unknown $user
     * @return integer
     */
    public function user_may_read($user) {

        if ($user->is_system()) {
            return AIR2_AUTHZ_IS_SYSTEM;
        }

        // owner
        if ($this->ssearch_cre_user == $user->user_id) {
            return AIR2_AUTHZ_IS_OWNER;
        }


        // org (more complex)
        // TODO refactor to execute minimal SQL.
        $creator_org_ids = array_keys($this->CreUser->get_authz());
        $user_org_ids = array_keys($user->get_authz());
        if ($this->ssearch_public_flag && count(array_intersect($creator_org_ids, $user_org_ids))) {
            return AIR2_AUTHZ_IS_ORG;
        }

        // project (most complex)
        $proj_org_ids = $this->_get_proj_org_ids();
        //diag("ssearch_id: " . $this->ssearch_id);
        //diag("user_org_ids:" . var_export( $user_org_ids, true ) );
        //diag("proj_org_ids:" . var_export( $proj_org_ids, true ) );
        if (count(array_intersect($user_org_ids, $proj_org_ids))) {
            return AIR2_AUTHZ_IS_PROJECT;
        }

        return AIR2_AUTHZ_IS_DENIED;
    }


    /**
     *
     *
     * @param User    $user
     * @return authz integer
     */
    public function user_may_write($user) {
        if ($user->is_system()) {
            return AIR2_AUTHZ_IS_SYSTEM;
        }
        if (!$this->ssearch_id) {
            return AIR2_AUTHZ_IS_NEW;
        }
        if ($this->ssearch_cre_user == $user->user_id) {
            return AIR2_AUTHZ_IS_OWNER;
        }

        return AIR2_AUTHZ_IS_DENIED;
    }


    /**
     * Calls user_may_write().
     *
     * @param User    $user
     * @return authz integer
     */
    public function user_may_manage($user) {
        return $this->user_may_write($user);
    }


}
